package com.cskaoyan.mall.search.service.impl;

import com.cskaoyan.mall.commons.exception.ExceptionProcessorUtils;
import com.cskaoyan.mall.dto.ProductDto;
import com.cskaoyan.mall.search.consts.SearchRetCode;
import com.cskaoyan.mall.search.converter.ProductConverter;
import com.cskaoyan.mall.search.dto.SearchRequest;
import com.cskaoyan.mall.search.dto.SearchResponse;
import com.cskaoyan.mall.search.entity.ItemDocument;
import com.cskaoyan.mall.search.entity.ItemDocumentStandardText;
import com.cskaoyan.mall.search.exception.SearchException;
import com.cskaoyan.mall.search.repository.ProductRepository;
import com.cskaoyan.mall.search.service.ProductSearchService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: 牟治宇
 * @description 搜索实现
 * @date: 2022/8/6 12:26
 */
@Service
@Slf4j
public class ProductSearchServiceImpl implements ProductSearchService {

    @Autowired
    ElasticsearchRestTemplate restTemplate;
    @Autowired
    ProductRepository productRepository;
    @Autowired
    ProductConverter productConverter;



    @Override
    public SearchResponse search(SearchRequest request) {
        SearchResponse<ProductDto> response = new SearchResponse<>();

        try {
            String key = request.getKeyword();

            Integer priceLte = request.getPriceLte();
            Integer priceGt = request.getPriceGt();

            //进行判空
            if (request.getPriceGt() == null){
                request.setPriceGt(0);
            }

            if (request.getPriceLte() == null){
                request.setPriceLte(Integer.MAX_VALUE);
            }
            Integer page = request.getCurrentPage();
            Integer size = request.getPageSize();
            String sort = request.getSort();

            NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

            //queryString查询
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(key).field("title").field("sellPoint");

            //must查询
            // BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            // MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title",key);

            boolQueryBuilder.must(queryStringQueryBuilder);

            RangeQueryBuilder priceRange = QueryBuilders.rangeQuery("price").gte(priceGt).lte(priceLte);
            boolQueryBuilder.filter(priceRange);

            queryBuilder.withQuery(boolQueryBuilder);

            PageRequest pageInfo = null;
            if ("".equals(sort)) {
                log.info("综合排序");
                pageInfo = PageRequest.of(page-1, size);
            } else if ("1".equals(sort)) {
                log.info("价格从低到高");
                pageInfo = PageRequest.of(page-1, size, Sort.by(Sort.Order.asc("price")));
            } else if ("-1".equals(sort)) {
                log.info("价格从高到低");
                pageInfo = PageRequest.of(page-1, size, Sort.by(Sort.Order.desc("price")));
            } else {
                log.error("ProductSearchServiceImpl.search Occur Exception : 排序参数非法");
                throw new SearchException(SearchRetCode.STRING_EMPTY.getCode(), SearchRetCode.STRING_EMPTY.getMsg());
            }
            queryBuilder.withPageable(pageInfo);
            // 高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title").field("sellPoint").preTags("<font color='green' size='5'>").postTags("</font>");
            queryBuilder.withHighlightBuilder(highlightBuilder);

            // 发起搜索请求
            SearchHits<ItemDocument> searchHits = restTemplate.search(queryBuilder.build(), ItemDocument.class);
            List<ProductDto> productDtos = new ArrayList<>();
            long total = searchHits.getTotalHits();

            List<SearchHit<ItemDocument>> hits = searchHits.getSearchHits();
            hits.forEach(hit -> {
                ItemDocument itemDocument = hit.getContent();
                ProductDto productDto = productConverter.item2Dto(itemDocument);
                List<String> title = hit.getHighlightField("title");
                if (title != null && title.size() > 0) {
                    productDto.setProductName(title.get(0));
                }
                List<String> sellPoint = hit.getHighlightField("sellPoint");
                if (sellPoint != null && sellPoint.size() > 0) {
                    productDto.setSubTitle(sellPoint.get(0));
                }
                productDtos.add(productDto);
            });
            response.setTotal(total);
            response.setData(productDtos);
            response.setCode(SearchRetCode.SUCCESS.getCode());
            response.setMsg(SearchRetCode.SUCCESS.getMsg());
        } catch (Exception e) {
            log.error("ProductSearchServiceImpl.search Occur Exception :" + e);
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }

        return response;
    }

    @Override
    public SearchResponse fuzzySearch(SearchRequest request) {
        SearchResponse<ProductDto> response = null;
        try {
            String keyword = request.getKeyword();

            PageRequest pageRequest = PageRequest.of(0,10);

            // 根据关键字查询
            Page<ItemDocument> itemDocuments = productRepository.testSearchPage(keyword, pageRequest);


            List<ProductDto> productDtos = new ArrayList<>();
            for (ItemDocument itemDocument : itemDocuments) {
                ProductDto productDto = productConverter.item2Dto(itemDocument);
                productDtos.add(productDto);
            }
            response = new SearchResponse<>();
            response.setData(productDtos);
            response.setCode(SearchRetCode.SUCCESS.getCode());
        } catch (Exception e) {
            log.error("ProductSearchServiceImpl.fuzzySearch Occur Exception :" + e);
            e.printStackTrace();
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }

        return response;
    }
}
